1
|
|
|
import spacetime from 'spacetime'; |
2
|
|
|
import { getGlobalConfiguration, SETTINGS_websiteAutoTimeConversion } from '../configuration/configuration'; |
3
|
|
|
import * as core from '../utils/aniwatchCore'; |
4
|
|
|
import * as helper from '../utils/helpers'; |
5
|
|
|
|
6
|
|
|
const __alteredNodes = []; |
7
|
|
|
const DAYS = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday']; |
8
|
|
|
|
9
|
|
|
export function init(): void { |
10
|
|
|
getGlobalConfiguration().getProperty(SETTINGS_websiteAutoTimeConversion, value => { |
11
|
|
|
if (value) { |
12
|
|
|
// The regexp pattern matches anything except the airing page. |
13
|
|
|
// This is because we would have to restructure the complete site to update time data. |
14
|
|
|
// Additionally, there is a big hint that all data would be UTC+1 |
15
|
|
|
core.runAfterLoad(() => { |
16
|
|
|
updateTimestamps(document.documentElement); |
17
|
|
|
}, "^/(?!airing).*$"); |
18
|
|
|
|
19
|
|
|
core.runAfterLocationChange(() => { |
20
|
|
|
updateTimestamps(document.documentElement); |
21
|
|
|
}, "^/(?!airing).*$"); |
22
|
|
|
|
23
|
|
|
core.registerScript((node: Node) => { |
24
|
|
|
updateTimestamps(node); |
25
|
|
|
}, "^/(?!airing).*$"); |
26
|
|
|
} |
27
|
|
|
}); |
28
|
|
|
} |
29
|
|
|
|
30
|
|
|
function getSpaceDateTimeFormat(use24Format: boolean): string { |
31
|
|
|
return `${getSpaceDateFormat()} ${getSpaceTimeFormat(use24Format)}`; |
32
|
|
|
} |
33
|
|
|
|
34
|
|
|
function getSpaceTimeFormat(use24Format: boolean): string { |
35
|
|
|
if (use24Format) { |
36
|
|
|
return '{time-24}'; |
37
|
|
|
} |
38
|
|
|
|
39
|
|
|
return '{time}'; |
40
|
|
|
} |
41
|
|
|
|
42
|
|
|
function getSpaceDateFormat(): string { |
43
|
|
|
return '{date}. {month-short} {year}'; |
44
|
|
|
} |
45
|
|
|
|
46
|
|
|
function tryUpdateDateTime(node: Node): boolean { |
47
|
|
|
const REG_DATETIME = /(\d{2}(\/|\.)){2}\d{4} *\d?\d:\d{2}( (AM|PM))?/g; |
48
|
|
|
const REG_TIME = /\d?\d:\d{2}/; |
49
|
|
|
const REG_AMPM = /\s(am|pm)/i; |
50
|
|
|
|
51
|
|
|
let hits = Array.from(node.textContent.matchAll(REG_DATETIME), match => match[0]); |
52
|
|
|
|
53
|
|
|
if (hits.length === 0) { |
54
|
|
|
return false; |
55
|
|
|
} |
56
|
|
|
|
57
|
|
|
hits.forEach(hit => { |
58
|
|
|
let use24Format = false; |
59
|
|
|
let processedStr = hit |
60
|
|
|
|
61
|
|
|
// string must be converted into 12h format |
62
|
|
|
if (processedStr.search(REG_AMPM) < 0) { |
63
|
|
|
let timeStr = processedStr.match(REG_TIME)[0]; |
64
|
|
|
let hm = timeStr.split(':'); |
65
|
|
|
let hour = parseInt(hm[0]); |
66
|
|
|
|
67
|
|
|
if (hour >= 12) { |
68
|
|
|
timeStr = timeStr.replace(`${hour}:`, `${hour - 12}:`); |
69
|
|
|
timeStr += 'pm'; |
70
|
|
|
} |
71
|
|
|
else { |
72
|
|
|
timeStr += 'am'; |
73
|
|
|
} |
74
|
|
|
|
75
|
|
|
processedStr = processedStr.replace(REG_TIME, timeStr); |
76
|
|
|
use24Format = true; |
77
|
|
|
} |
78
|
|
|
|
79
|
|
|
// if time has a space before am/pm, this has to be removed for spacetime |
80
|
|
|
processedStr = processedStr.replace(REG_AMPM, '$1'); |
81
|
|
|
|
82
|
|
|
let datetime = spacetime(processedStr, 'UTC+1', { dmy: true }); |
83
|
|
|
datetime = datetime.goto(spacetime().tz); |
84
|
|
|
let replaceText = String(datetime.format(getSpaceDateTimeFormat(use24Format))); |
85
|
|
|
|
86
|
|
|
node.textContent = node.textContent.replace(hit, replaceText); |
87
|
|
|
}); |
88
|
|
|
|
89
|
|
|
return true; |
90
|
|
|
} |
91
|
|
|
|
92
|
|
|
function tryUpdateDate(node: Node): boolean { |
93
|
|
|
const REG_DATE = /(\d{2}(\/|\.)){2}\d{4}/g; |
94
|
|
|
|
95
|
|
|
let hits = Array.from(node.textContent.matchAll(REG_DATE), match => match[0]); |
96
|
|
|
|
97
|
|
|
if (hits.length === 0) { |
98
|
|
|
return false; |
99
|
|
|
} |
100
|
|
|
|
101
|
|
|
hits.forEach(hit => { |
102
|
|
|
let datetime = spacetime(hit, 'UTC+1', { dmy: true }); |
103
|
|
|
datetime = datetime.goto(spacetime().tz); |
104
|
|
|
let replaceText = String(datetime.format(getSpaceDateFormat())); |
105
|
|
|
|
106
|
|
|
node.textContent = node.textContent.replace(hit, replaceText); |
107
|
|
|
}); |
108
|
|
|
|
109
|
|
|
return true; |
110
|
|
|
} |
111
|
|
|
|
112
|
|
|
function tryUpdateTime(node: Node): boolean { |
113
|
|
|
const REG_TIME = /\d?\d:\d{2}( (AM|PM))?/g; |
114
|
|
|
const REG_AMPM = /\s(am|pm)/i; |
115
|
|
|
|
116
|
|
|
let hits = Array.from(node.textContent.matchAll(REG_TIME), match => match[0]); |
117
|
|
|
|
118
|
|
|
if (hits.length === 0) { |
119
|
|
|
return false; |
120
|
|
|
} |
121
|
|
|
|
122
|
|
|
hits.forEach(hit => { |
123
|
|
|
let use24Format = false; |
124
|
|
|
let processedStr = hit |
125
|
|
|
|
126
|
|
|
// string must be converted into 12h format |
127
|
|
|
if (processedStr.search(REG_AMPM) < 0) { |
128
|
|
|
let timeStr = processedStr.match(REG_TIME)[0]; |
129
|
|
|
let hm = timeStr.split(':'); |
130
|
|
|
let hour = parseInt(hm[0]); |
131
|
|
|
|
132
|
|
|
if (hour >= 12) { |
133
|
|
|
timeStr = timeStr.replace(`${hour}:`, `${hour - 12}:`); |
134
|
|
|
timeStr += 'pm'; |
135
|
|
|
} |
136
|
|
|
else { |
137
|
|
|
timeStr += 'am'; |
138
|
|
|
} |
139
|
|
|
|
140
|
|
|
processedStr = processedStr.replace(REG_TIME, timeStr); |
141
|
|
|
use24Format = true; |
142
|
|
|
} |
143
|
|
|
|
144
|
|
|
// if time has a space before am/pm, this has to be removed for spacetime |
145
|
|
|
processedStr = processedStr.replace(REG_AMPM, '$1'); |
146
|
|
|
|
147
|
|
|
let datetime = spacetime(); |
148
|
|
|
datetime = datetime.goto('UTC+1'); |
149
|
|
|
datetime = datetime.time(processedStr); |
150
|
|
|
datetime = datetime.goto(spacetime().tz); |
151
|
|
|
let replaceText = String(datetime.format(getSpaceTimeFormat(use24Format))); |
152
|
|
|
|
153
|
|
|
node.textContent = node.textContent.replace(hit, replaceText); |
154
|
|
|
|
155
|
|
|
// SPECIAL CASE: Anime has the day written in broadcast bade. This may be different in another timezone |
156
|
|
|
let tzMeta = spacetime().timezone(); |
157
|
|
|
let originalH = datetime.hour() - tzMeta.current.offset + 1; |
158
|
|
|
|
159
|
|
|
let dOffset = 0; |
160
|
|
|
// we moved to next day |
161
|
|
|
if (originalH < 0) { |
162
|
|
|
dOffset = 1; |
163
|
|
|
} |
164
|
|
|
// we moved to previous day |
165
|
|
|
else if (originalH > 24) { |
166
|
|
|
dOffset = -1; |
167
|
|
|
} |
168
|
|
|
|
169
|
|
|
// if day changed |
170
|
|
|
if (dOffset != 0) { |
171
|
|
|
let dayNode = (node.parentNode as Element)?.previousElementSibling; |
172
|
|
|
if (helper.assigned(dayNode)) { |
173
|
|
|
for (let i = 0; i < DAYS.length; i++) { |
174
|
|
|
if (dayNode.textContent.indexOf(DAYS[i]) >= 0) { |
175
|
|
|
dayNode.textContent = dayNode.textContent.replace(DAYS[i], DAYS[(i + DAYS.length + dOffset) % DAYS.length]); // add DAYS.length to avoid negative numbers in the modulo operation |
176
|
|
|
break; |
177
|
|
|
} |
178
|
|
|
} |
179
|
|
|
} |
180
|
|
|
} |
181
|
|
|
}); |
182
|
|
|
|
183
|
|
|
return true; |
184
|
|
|
} |
185
|
|
|
|
186
|
|
|
function tryUpdateTimeZone(node: Node): boolean { |
187
|
|
|
const HINT_UTC = 'UTC+1'; |
188
|
|
|
if (node.textContent === HINT_UTC) { |
189
|
|
|
let tzMeta = spacetime().timezone(); |
190
|
|
|
|
191
|
|
|
node.textContent = `${tzMeta.name} (UTC${tzMeta.current.offset >= 0 ? '+' : ''}${tzMeta.current.offset})`; |
192
|
|
|
|
193
|
|
|
return true; |
194
|
|
|
} |
195
|
|
|
|
196
|
|
|
return false; |
197
|
|
|
} |
198
|
|
|
|
199
|
|
|
function updateTimestamps(node) { |
200
|
|
|
let nodes = helper.findTextNodes(node); |
201
|
|
|
|
202
|
|
|
nodes.forEach(node => { |
203
|
|
|
// avoid double updates |
204
|
|
|
if (__alteredNodes.indexOf(node) >= 0) { |
205
|
|
|
return; |
206
|
|
|
} |
207
|
|
|
|
208
|
|
|
if (tryUpdateDateTime(node)) { |
209
|
|
|
__alteredNodes.push(node); |
210
|
|
|
return; |
211
|
|
|
} |
212
|
|
|
|
213
|
|
|
if (tryUpdateDate(node)) { |
214
|
|
|
__alteredNodes.push(node); |
215
|
|
|
return; |
216
|
|
|
} |
217
|
|
|
|
218
|
|
|
if (tryUpdateTime(node)) { |
219
|
|
|
__alteredNodes.push(node); |
220
|
|
|
return; |
221
|
|
|
} |
222
|
|
|
|
223
|
|
|
if (tryUpdateTimeZone(node)) { |
224
|
|
|
__alteredNodes.push(node); |
225
|
|
|
return; |
226
|
|
|
} |
227
|
|
|
}); |
228
|
|
|
} |